#include <gtest/gtest.h>
#include <thread>
#include <chrono>
#include <atomic>
#include <future>
#include <mutex>
#include <pthread.h> // POSIX 线程接口，用于测试中主动取消线程

// 仅用于测试访问私有成员
#define private public
#define protected public
#include "ThreadPool.h"
#undef private
#undef protected

// 设置线程池模式
TEST(ThreadPoolTest, SetMode) {
  ThreadPool pool;
  pool.setMode(PoolMode::MODE_CACHED);

  EXPECT_EQ(pool.poolMode_, PoolMode::MODE_CACHED);
}

// 设置任务队列阈值
TEST(ThreadPoolTest, SetTaskQueueThreshold) {
  ThreadPool pool;
  pool.setTaskQueMaxThreshHold(256);

  EXPECT_EQ(pool.taskQueThreshHold_, 256);
}

// 验证 start() 创建并启动指定数量的线程。
// 注意：ThreadPool::threadFunc() 内部是死循环，测试中需使用 pthread_cancel 主动结束线程。
TEST(ThreadPoolTest, StartCreatesThreads) {
  ThreadPool pool;
  constexpr std::size_t kThreads = 2;

  pool.start(kThreads);

  ASSERT_EQ(pool.threads_.size(), kThreads);
  for (auto &thPtr : pool.threads_) {
    ASSERT_TRUE(thPtr);
  }

  // 略等片刻，确保线程执行至 threadFunc() 并进入等待队列的逻辑
  std::this_thread::sleep_for(std::chrono::milliseconds(20));

  // 线程函数无退出条件，这里使用 pthread_cancel 请求终止
  for (auto &thPtr : pool.threads_) {
    ASSERT_TRUE(thPtr);
    pthread_cancel(thPtr->worker_.native_handle());
  }

  // 取消后必须 join，确保线程资源被正确回收
  for (auto &thPtr : pool.threads_) {
    if (thPtr) {
      thPtr->join();
    }
  }
  pool.threads_.clear();
}

// submitTask() 在队列未满时应成功入队
TEST(ThreadPoolTest, SubmitTaskPushesIntoQueue) {
  ThreadPool pool;
  // 队列阈值设置为 2，方便验证入队计数变化
  pool.setTaskQueMaxThreshHold(2);

  // 空操作任务，run() 中不执行任何逻辑
  class NoOpTask : public Task {
  public:
    void run() override {}
  };
  auto task = std::make_shared<NoOpTask>();

  EXPECT_EQ(pool.taskQue_.size(), 0);
  EXPECT_EQ(pool.taskSize_.load(), 0);

  // 第一次提交，队列未满，应立即成功入队
  pool.submitTask(task);
  EXPECT_EQ(pool.taskQue_.size(), 1);
  EXPECT_EQ(pool.taskSize_.load(), 1);

  // 第二次提交仍未超过阈值，应继续成功
  pool.submitTask(task);
  EXPECT_EQ(pool.taskQue_.size(), 2);
  EXPECT_EQ(pool.taskSize_.load(), 2);
}

// submitTask() 在队列已满时会阻塞等待 1 秒，超时后放弃入队并返回
TEST(ThreadPoolTest, SubmitTaskFailsWhenQueueIsFull) {
  ThreadPool pool;
  pool.setTaskQueMaxThreshHold(1); // 阈值设为 1，便于构造“队列已满”

  class NoOpTask : public Task {
  public:
    void run() override {}
  };
  auto task = std::make_shared<NoOpTask>();

  // 首次提交成功，队列被占满
  pool.submitTask(task);
  ASSERT_EQ(pool.taskQue_.size(), 1);
  ASSERT_EQ(pool.taskSize_.load(), 1);

  // 第二次提交将阻塞等待 notFull_，约 1 秒后超时返回
  auto start = std::chrono::steady_clock::now();
  pool.submitTask(task);
  auto end = std::chrono::steady_clock::now();

  // 验证等待时间接近 1 秒（允许一定误差）
  EXPECT_GE(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(), 900);

  // 任务提交失败后，队列和计数保持不变
  EXPECT_EQ(pool.taskQue_.size(), 1);
  EXPECT_EQ(pool.taskSize_.load(), 1);
}

// threadFunc() 应正确消费队列中的任务并执行 run()
TEST(ThreadPoolTest, ThreadFuncConsumesTaskAndRunsIt) {
  ThreadPool pool;

  // runCount 用于确认任务是否执行；promise 用于同步主线程等待结果
  std::atomic_int runCount{0};
  std::promise<void> taskExecuted;
  std::future<void> taskExecutedFuture = taskExecuted.get_future();

  // 自定义任务：执行时递增计数器，并通过 promise 通知主线程
  class CountingTask : public Task {
  public:
    CountingTask(std::atomic_int &counter, std::promise<void> &signal)
        : counter_(counter), signal_(signal) {}

    void run() override {
      counter_.fetch_add(1, std::memory_order_relaxed);
      signal_.set_value();
    }

  private:
    std::atomic_int &counter_;
    std::promise<void> &signal_;
  };
  auto countingTask = std::make_shared<CountingTask>(runCount, taskExecuted);

  // 手动入队一个任务，同时维护 taskSize_ 与条件变量一致性
  {
    std::lock_guard<std::mutex> lk(pool.taskQueMtx_);
    pool.taskQue_.push(countingTask);
    pool.taskSize_.fetch_add(1, std::memory_order_relaxed);
  }
  pool.notEmpty_.notify_one(); // 唤醒阻塞在 notEmpty_ 上的消费者

  // 启动独立线程直接执行 threadFunc()，模拟线程池内部的工作线程
  std::thread worker([&pool] {
    pool.threadFunc();
  });

  // 等待任务执行完成
  EXPECT_EQ(taskExecutedFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready);
  EXPECT_EQ(runCount.load(std::memory_order_relaxed), 1);
  EXPECT_EQ(pool.taskSize_.load(std::memory_order_relaxed), 0);
  EXPECT_TRUE(pool.taskQue_.empty());

  // threadFunc() 是无限循环，测试结束后需主动取消并 join
  pthread_cancel(worker.native_handle());
  worker.join();
}